﻿<h1>介绍</h1>
每个应用都需要保存一些设置信息，并在需要的地方获取它。abp提供一个健壮的基础架构来保存/检索应用级别、租户级别和用户级别的设置，且服务端和客户端都提供了操作设置的api
设置以key-value的字符串形式保存在数据或其它存储中，非字符串的设置项可以转换成字符串再进行存储

<h1>关于ISettingStore接口</h1>
它是abp基础项目定义的一个接口，用来做设置的底层存取工作，虽然我们可以自己提供实现，但是Module Zero(abp的默认实现项目)已经对它做了实现。
如果我们没有提供实现也没有使用Module Zero提供的实现，那么abp将默认使用应用默认的配置文件(web.config or app.config)，
但是这种情况下只能手动修改设定值，且“设置级别”功能也无法使用了，因为若用户或租户很多时，不可能在web.config存储那么多数据

<h1>定义设置</h1>
不同的模块可以定义不同的“设置项”，通过实现SettingProvider的自定义类来完成“设置项”的定义，如下：
<pre>
public class MySettingProvider : SettingProvider
{
    public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
    {
        return new[]
        {
            new SettingDefinition(
                "SmtpServerAddress",
                "127.0.0.1"
            ),
            new SettingDefinition(
                "PassiveUsersCanNotLogin",
                "true",
                scopes: SettingScopes.Application | SettingScopes.Tenant
            ),
            new SettingDefinition(
                "SiteColorPreference",
                "red",
                scopes: SettingScopes.User,
                clientVisibilityProvider: new VisibleSettingClientVisibilityProvider()
            )
        };
    }
}
</pre>
GetSettingDefinitions方法返回成员为SettingDefinition类型的集合，这个类就表示一个“设置项”，有如下成员：
<ul>
    <li>Name：必须字段 设置项的全局唯一名称，推荐使用常量</li>
    <li>Default value：默认值，可以为空</li>
    <li>Scopes：级别/范围，文章下面部分详细讲解</li>
    <li>Display name：在界面中显示的本地化的设置的名称</li>
    <li>Description：描述信息，可以用来提示用户此设置项的作用</li>
    <li>Group：设置分组，只是方便在界面中区分显示，不用做设置的管理</li>
    <li>ClientVisibilityProvider：是否应用到客户端的api中，如果为false，则客户端js无法访问</li>
    <li>isInherited：是否由租户、用户继承，比如应用级别的设置可以被租户或用户继承</li>
    <li>customData：可以通过此属性来保存我们的自定义信息</li>
</ul>
创建setting provider之后需要进行注册
<pre>
Configuration.Settings.Providers.Add<MySettingProvider>();
</pre>
设置提供程序通过依赖项注入自动注册。设置提供程序可以注入任何依赖项(如存储库)，以使用其他源构建设置定义。

<h1>Setting scope 设置级别/范围</h1>
<ul>
    <li>
        Application：应用程序范围设置用于与用户/租户无关的设置。例如，我们可以定义一个名为“SmtpServerAddress”的设置，
        以便在发送电子邮件时获取服务器的IP地址。如果该设置只有一个值(不是根据用户进行更改)，那么我们可以将其定义为应用程序范围。
    </li>
    <li>Tenant：如果应用程序是多租户的，我们可以定义特定于租户的设置。</li>
    <li>User：我们可以使用用户范围的设置来存储/获取特定于每个用户的设置的值。</li>
</ul>
SettingScopes枚举定义了FlagsAttribute，因此我们可以在同一个设置项上应用多个Scope<br />
默认情况下，设置范围是分层的(除非您将继承设置为false)。例如，如果我们将一个设置的范围定义为“Application | Tenant | User”，并试图获取该设置的当前值;
<ul>
    <li>先尝试查找用户设置</li>
    <li>再尝试查找租户设置</li>
    <li>再尝试查找应用级别的设置</li>
    <li>如果上面都没找到就取设置项的默认值</li>
</ul>
默认值可以是null或空字符串。建议在可能的情况下为设置提供默认值。

<h1>重写设置定义</h1>
模块A依赖模块B，那么在模块A中可以通过context.Manager覆盖模块B中定义的设置项

<h1>获取设置的值</h1>
服务端和客户端都提供了相应的API

<h2>服务端</h2>
在需要操作设置的类中注入ISettingManager
<pre>
//Getting a boolean value (async call)
var value1 = await SettingManager.GetSettingValueAsync<bool>("PassiveUsersCanNotLogin");

//Getting a string value (sync call)
var value2 = SettingManager.GetSettingValue("SmtpServerAddress");
</pre>
一些基类Controller 服务基类 等 都提供了注入好的SettingManager.可以直接使用


<h2>ISettingDefinitionManager</h2>
在需要的地方注入它，主要是用来获取“设置项定义”，参考上面的SettingProvider

<h2>客户端</h2>
设置项定义的属性ClientVisibilityProvider用来觉得设置项是否在客户端可以使用，它是 ISettingClientVisibilityProvider类型的，此接口有如下实现：
<ul>
    <li>VisibleSettingClientVisibilityProvider：使设置项对客户端可见</li>
    <li>HiddenSettingClientVisibilityProvider：使设置项对客户端不可见</li>
    <li>RequiresAuthenticationSettingClientVisibilityProvider：此设置在用户登陆后才可见</li>
    <li>RequiresPermissionSettingClientVisibilityProvider：需要用户有某个权限时此设置才在客户端可见</li>
</ul>
参考上面的说明后，若设置在客户端可见时可以通过下面的方式在客户端访问设置
<pre>
var currentColor = abp.setting.get("SiteColorPreference");
</pre>
还有getInt,getBoolean,也可以通过abp.setting.values获取所有设置值，注意若服务端修改了设置值，客户端需要刷新

<h1>修改设置值</h1>
ISettingManager提供了ChangeSettingForApplicationAsync, ChangeSettingForTenantAsync 和 ChangeSettingForUserAsync等方法及其同步版本来修改设置值

<h1>关于缓存</h1>
SettingManager在服务端缓存值，所以不要直接通过仓储查询或修改“设置值”